package lv.pig.base.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

public final class CommonUtils
{
    private static final String UNKNOWN_STRING = "unknown";
    
    private static Logger logger = LoggerFactory.getLogger(CommonUtils.class);
    
    /**
     * <获取网址的域名+端口>
     * <功能详细描述>
     * @param url
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String findDomain(String url)
    {
        Pattern p =
            Pattern.compile("[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\\.?(:\\d+)?",
                Pattern.CASE_INSENSITIVE);
        Matcher matcher = p.matcher(url);
        if (matcher.find())
        {
            return matcher.group();
        }
        return "";
    }
    
    /**
     * <获取当前时间>
     * <功能详细描述>
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Date current(String format)
    {
        Calendar c = Calendar.getInstance();
        try
        {
            return new SimpleDateFormat(format).parse(format(c.getTime(), format));
        }
        catch (ParseException e)
        {
            logger.error("error", e);
            return null;
        }
    }
    
    /**
     * <格式化时间>
     * <功能详细描述>
     * @param date
     * @param format
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String format(Date date, String format)
    {
        return new SimpleDateFormat(format).format(date);
    }

    
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void addAll(List source, List append)
    {
        if (!CollectionUtils.isEmpty(append))
        {
            source.addAll(append);
        }
    }
    
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void add(List source, Object append)
    {
        if (null != append)
        {
            source.add(append);
        }
    }
    
    /**
     * <获取主机信息>
     * <功能详细描述>
     * @param request
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String buildRequestString(HttpServletRequest request)
    {
        StringBuffer sb = new StringBuffer();
        
        final String userAgent = request.getHeader("user-agent");
        
        String ip = request.getHeader("x-forwarded-for");
        if (StringUtils.isEmpty(ip) || UNKNOWN_STRING.equalsIgnoreCase(ip))
        {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN_STRING.equalsIgnoreCase(ip))
        {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN_STRING.equalsIgnoreCase(ip))
        {
            ip = request.getRemoteAddr();
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN_STRING.equalsIgnoreCase(ip))
        {
            ip = request.getHeader("http_client_ip");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN_STRING.equalsIgnoreCase(ip))
        {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        // 如果是多级代理，那么取第一个ip为客户ip
        if (ip != null && ip.indexOf(",") != -1)
        {
            ip = ip.substring(ip.lastIndexOf(",") + 1, ip.length()).trim();
        }
        sb.append("\n client ip:" + ip);
        sb.append("\n userAgent:" + userAgent);
        return sb.toString();
    }
    
    /**
     * <获取文件大小>
     * <功能详细描述>
     * @param url
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static final long getFileSize(String url)
    {
        URL u;
        URLConnection uc;
        long bytes = 0l;
        try
        {
            u = new URL(url);
            uc = u.openConnection();
            bytes = uc.getContentLength();
        }
        catch (MalformedURLException e)
        {
            
        }
        catch (IOException e)
        {
            
        }
        return bytes;
    }
    
    /**
     * <获取本机的ip地址> <功能详细描述>
     * 
     * @param supportIp6 是否获取ipV6的地址
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String getHostIp(boolean supportIp6)
    {
        StringBuffer sb = new StringBuffer();
        
        try
        {
            Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
            while (en.hasMoreElements())
            {
                NetworkInterface ni = en.nextElement();
                Enumeration<InetAddress> ee = ni.getInetAddresses();
                while (ee.hasMoreElements())
                {
                    InetAddress ia = ee.nextElement();
                    
                    if (ia instanceof Inet4Address && !"127.0.0.1".equals(ia.getHostAddress()))
                    {
                        sb.append(ia.getHostAddress() + ";");
                    }
                    else if (supportIp6 && ia instanceof Inet6Address && !"0:0:0:0:0:0:0:1".equals(ia.getHostAddress()))
                    {
                        
                        sb.append(ia.getHostAddress() + ";");
                        
                    }
                    
                }
            }
        }
        catch (SocketException e)
        {
            logger.info("获取本机ip错误!" + e.getMessage());
        }
        return sb.toString();
    }
    
    /**
     * <获取文件md5>
     * <功能详细描述>
     * @param filePath
     * @return
     * @throws IOException
     * @see [类、类#方法、类#成员]
     */
    public static String getMD5(String filePath)
        throws IOException
    {
        FileInputStream im = new FileInputStream(filePath);
        return DigestUtils.md5Hex(im);
    }
    
    public static String build(Operator o, String fieldName)
    {
        return o+"_"+fieldName;
    }
    
    @SuppressWarnings("unchecked")
    public static <T> Specification<T> buildSpecification(Map<String, Object> searchParams, Class<T> t)
    {
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        Specification<T> spec = (Specification<T>)DynamicSpecifications.bySearchFilter(filters.values(), t.getClass());
        return spec;
    }
    
    public static Pageable buildPage(int pageNo, int pageSize)
    {
        return buildPage(pageNo, pageSize, null);
    }
    
    public static Pageable buildPage(int pageNo, int pageSize, Map<String, Direction> sorts)
    {
        Sort sort = buildSort(sorts);
        return new PageRequest(pageNo - 1, pageSize, sort);
    }
    
    private static Sort buildSort(Map<String, Direction> sorts)
    {
        Sort sort = null;
        if (!CollectionUtils.isEmpty(sorts))
        {
            for (String orderBy : sorts.keySet())
            {
                if (null == sort)
                {
                    sort = new Sort(null == sorts.get(orderBy) ? Direction.ASC : sorts.get(orderBy), orderBy);
                }
                else
                {
                    sort.and(new Sort(null == sorts.get(orderBy) ? Direction.ASC : sorts.get(orderBy), orderBy));
                }
            }
        }
        
        return sort;
    }
}
